//
//  RACSignerVC.m
//  ReactiveObjCDemo
//
//  Created by xth on 2017/12/6.
//  Copyright © 2017年 xth. All rights reserved.
//

#import "RACSignerVC.h"

@interface RACSignerVC ()

@property (nonatomic, copy) NSString *curTag;

@end

@implementation RACSignerVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self createSignal];
    
    [self createSignalOperation];
    
    [self createTimeSignal];
    
    [self createSignalOther];
    
    [self craeteMergeSignal];
    
    [self createSignalGroup];
    
    [self createSignalZip];
}


- (void)createSignal {
    
    //完整创建RACSignal 包含三部分sendError（不一定要有），sendNext（可多个），sendComplete（不一定有）
    //RACSubscriber:表示订阅者的意思
    
    self.curTag = @"error";
    
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSError *error;
        if ([self.curTag isEqualToString:@"error"]) {
            error = [[NSError alloc] initWithDomain:@"myError" code:400 userInfo:nil];
            [subscriber sendError:error];
        } else {
            [subscriber sendNext:@"1"];
            [subscriber sendNext:@"2"];
            [subscriber sendNext:@"3"];
        }
        
        //发送给订阅者完成
        [subscriber sendCompleted];

        return [RACDisposable disposableWithBlock:^{
            //RACDisposable 用于取消订阅或清理资源，当信号发送完成或者发送错误的时候，就会自动触发
            //使用场景：不想监听某个信号的时候，可以主动取消
            NSLog(@"执行清理");
        }];
    }];
    
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"当前值为：%@", x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"错误 ： %@", error);
    } completed:^{
        NSLog(@"完成");
    }];
}

- (void)createSignalOperation {
    
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"30"];
        [subscriber sendNext:@"500"];
        [subscriber sendNext:@"xx"];
        
        [subscriber sendCompleted];
        
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"执行清理");
        }];
    }];
    
    
    //filter过滤
    [[signal filter:^BOOL(id  _Nullable value) {
        if ([value isEqualToString:@"xx"]) {
            return YES;
        } else {
            return NO;
        }
    }]  subscribeNext:^(id  _Nullable x) {
        NSLog(@"filter当前值为：%@", x);
    }];
    
    //filter过滤后使用map进行转换，用map后 原来的值就会被转化
    [[[signal filter:^BOOL(id  _Nullable value) {
        if ([value isEqualToString:@"xx"]) {
            return NO;
        } else {
            return YES;
        }
    }] map:^id _Nullable(NSString *  _Nullable value) {
        return @(value.length);
    }] subscribeNext:^(NSNumber  * _Nullable x) {
        NSLog(@"当前的位数为：%ld", [x integerValue]);
    }];
    
    //flattenMap 用于把源信号内容映射成新的内容。
    [[signal flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
        return [RACSignal return:[NSString stringWithFormat:@"flattenMap当前输出为：%@",value]];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
    //map和flattenMap区别：
    //    1.FlatternMap中的Block返回信号。
    //    2.Map中的Block返回对象。
    //    3.开发中，如果信号发出的值不是信号，映射一般使用Map
    //    4.开发中，如果信号发出的值是信号，映射一般使用FlatternMap。
    
    
    //ingnore 忽略某个值
    [[signal ignore:@"xx"] subscribeNext:^(id  _Nullable x) {
        NSLog(@"忽略xx后 输出：%@", x);
    }];
    
    //ignoreValues 这个值比较极端，忽略所有值，只关心
    [[signal ignoreValues] subscribeNext:^(id  _Nullable x) {
        NSLog(@"ignoreValues 输出：%@", x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"ignoreValues error %@", error);
    } completed:^{
        NSLog(@"ignoreValues 完成");
    }];
    
    //take 从开始一共取N次的信号
    [[signal take:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"take - %@", x);
    }];
    
    //takeUntilBlock 对于每个next值，运行block，当block返回YES停止取值
    [[signal takeUntilBlock:^BOOL(id  _Nullable x) {
        if ([x isEqualToString:@"xx"]) {
            return YES;
        }
        return NO;
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"takeUntilBlock 值：%@", x);
    }];
    
    //takeLast 取最后N次的信号，前提条件，订阅者必须调用完成，否则不知道有多少信号
    [[signal takeLast:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"takeLast 获取的值：%@", x);
    }];
    
    //skip 跳过前N个信号，不接收
    [[signal skip:2] subscribeNext:^(id  _Nullable x) {
        NSLog(@"skip 获取的值：%@", x);
    }];
    
    //skipUntilBlock 同理，可以过滤掉某些信号，直接返回NO就可以过滤了
    [[signal skipUntilBlock:^BOOL(id  _Nullable x) {
        if ([x isEqualToString:@"1"]) {
            return NO;
        }
        return YES;
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"skipUntilBlock 获取的值：%@", x);
    }];
    
    
    //not 否
    [[[signal map:^id _Nullable(id  _Nullable value) {
        if ([value isEqualToString:@"xx"]) {
            return @(NO);
        }
        return @(YES);
    }] not] subscribeNext:^(NSNumber * _Nullable x) {
        NSLog(@"not 获取的值：%@", x);
    }];
    
    //startWith 起始位置增加相应的元素
    [[signal startWith:@"开始"] subscribeNext:^(id  _Nullable x) {
        NSLog(@"startWith 获取的值：%@", x);
    }];
    
    
    //reduceEach 聚合:用于信号发出的内容是元组，把信号发出元组的值聚合成一个值
    RACSignal *aSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:RACTuplePack(@1, @2)];
        [subscriber sendNext:RACTuplePack(@2, @3)];
        [subscriber sendNext:RACTuplePack(@3, @4)];
        
        return [RACDisposable disposableWithBlock:^ {
            NSLog(@"reduceEach 清理");
        }];
    }];
    
    [[aSignal reduceEach:^id(NSNumber *one, NSNumber *two){
        return [NSString stringWithFormat:@"(%@, %@)", one, two];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    }];
    
}

- (void)createTimeSignal {
    
    //设置定时，类似NSTimer，这里需设置token方式 interval 定时：每隔一段时间发出信号
//    [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
//        NSLog(@"----------吃药");
//    }];
    
    
    //超时炒作 timeout 超时  delay 延迟
    
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            
            NSLog(@"我快到了");
            [subscriber sendNext:@"我快到了"];
            [subscriber sendCompleted];
            return nil;
            
            //延迟2秒后执行next事件
        }] delay:2] subscribeNext:^(id  _Nullable x) {
            NSLog(@"我到了");
            [subscriber sendNext:@"我到了"];
            [subscriber sendCompleted];
        }];
        
        return nil;
    }] timeout:1 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@", x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"我走了");
    } completed:^{
        NSLog(@"完成");
    }];
}

- (void)createSignalOther {
    
    //retry 无限重试 或者重试N次，需要使用[subscriber sendError:nil];
    
    __block int i = 0;
    
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        NSLog(@"i = %d", i);
        
        if (i == 5) {
            [subscriber sendNext:[NSString stringWithFormat:@"%d", i]];
        } else {
            i++;
            [subscriber sendError:nil];
        }
        return nil;
    }] retry] subscribeNext:^(id  _Nullable x) {
        NSLog(@"retry 获取的值： %@", x);
    }];
    
    
    //获取信号直到某个信号执行完成
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"直到世界的尽头才能把我们分开"];
        return nil;
    }] takeUntil:[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"世界的尽头到了");
        });
        return nil;
    }]] subscribeNext:^(id  _Nullable x) {
        NSLog(@"takeUntil 获取的值：%@", x);
    }];
    
    //doNext: 执行Next之前，会先执行这个Block
    [[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"执行sendNext");
        [subscriber sendNext:@"执行sendNext"];
        [subscriber sendCompleted];
        return nil;
    }] doNext:^(id  _Nullable x) {
        NSLog(@"执行doNext");
    }] doCompleted:^{
        NSLog(@"执行doCompleted");
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"执行subscribeNext");
    }];
    
    
    //replay重放：当一个信号被多次订阅,反复播放内容
    
    RACSignal *rSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@2];
        return nil;
    }] replay];
    
    [rSignal subscribeNext:^(id x) {
        NSLog(@"replay 第一个订阅者%@",x);
    }];
    
    [rSignal subscribeNext:^(id x) {
        NSLog(@"replay 第二个订阅者%@",x);
    }];
    
    
    //throttle节流:当某个信号发送比较频繁时，可以使用节流，在某一段时间不发送信号内容，过了一段时间获取信号的最新内容发出。
    RACSubject *subject = [RACSubject subject];
    
    [[subject throttle:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"throttle--%@", x);
    }];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [subject sendNext:@"a"];
        [subject sendNext:@"b"]; //b是最新的，接收到b
    });
}


- (void)craeteMergeSignal {
    
    RACSignal *aSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"aSignal"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"aSignal清理了");
        }];
    }];
    
    RACSignal *bSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"bSignal"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"bSignal清理了");
        }];
    }];
    
    //这里监听aSignal和bSignal的信号值 combineLatest用法 reduce聚合:用于信号发出的内容是元组，把信号发出元组的值聚合成一个值
    [[RACSignal combineLatest:@[aSignal, bSignal] reduce:^id (NSString *a, NSString *b){
        return [NSString stringWithFormat:@"%@-%@", a, b];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"combineSignal (%@)", x);
    }];
    
    RACSignal *combineSignal = [aSignal combineLatestWith:bSignal];
    
    [combineSignal subscribeNext:^(id  _Nullable x) {
        //这里拿到是信号的对象
        NSLog(@"combineSignal (%@)", x);
    }];
    
    
    //then:用于连接两个信号，当第一个信号完成，才会连接then返回的信号。
    
    [[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendCompleted];
        return nil;
    }] then:^RACSignal * _Nonnull{
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            NSLog(@"第一步");
            [subscriber sendCompleted];
            return nil;
        }];
    }] then:^RACSignal * _Nonnull{
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            NSLog(@"第二步");
            [subscriber sendCompleted];
            return nil;
        }];
    }] subscribeCompleted:^{
        NSLog(@"完成");
    }];
    
    //collect 会把内容合并成一个数组  也就是元组
    RACSignal *arraySignal = [aSignal collect];
    [arraySignal subscribeNext:^(id x) {
        NSLog(@"collect 显示的值%@",x);
    }];
    
    //aggregateWithStart 运用 从哪个位置开始 进行顺序两值进行操作 最后只有一个被操作后的值
    
    [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@2];
        [subscriber sendNext:@12];
        [subscriber sendNext:@15];
        [subscriber sendCompleted];
        return nil;
    }] aggregateWithStart:@0 reduce:^id _Nonnull(id  _Nonnull running, id  _Nonnull next) {
        return [NSString stringWithFormat:@"%@-%@", running, next];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"aggregateWithStart -- %@", x);
    }];
}

//信号队列的使用 信号队列顾名思义就是将一组信号排成队列，挨个调用
-(void)createSignalGroup {
    
    //创建3个信号来模拟队列
    
    RACSignal *aSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"喜欢一个人"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal *bSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"直接去表白"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    RACSignal *cSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"成功在一起"];
        [subscriber sendCompleted];
        return nil;
    }];
    
    //连接队列：将几个信号放进一个组里，按顺序连接，每个信号必须执行sendCompleted方法后才能执行下一个信号
    [[[aSignal concat:bSignal] concat:cSignal] subscribeNext:^(id  _Nullable x) {
        NSLog(@"concat --- %@", x);
    }];
    
    //另外一种，信号合并队列
    [[RACSignal merge:@[aSignal, bSignal, cSignal]] subscribeNext:^(id  _Nullable x) {
        NSLog(@"merge --- %@", x);
    }];
}


//信号的压缩
- (void)createSignalZip {
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        [subscriber sendNext:@"我想你"];
        [subscriber sendNext:@"我不想你"];
        [subscriber sendNext:@"Test"];
        return nil;
    }];
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id subscriber) {
        [subscriber sendNext:@"嗯"];
        [subscriber sendNext:@"你豁我"];
        return nil;
    }];
    //    压缩具有一一对应关系,以2个信号中 消息发送数量少的为主对应
    [[signalA zipWith:signalB] subscribeNext:^(RACTuple* x) {
        //解包RACTuple中的对象
        RACTupleUnpack(NSString *stringA, NSString *stringB) = x;
        NSLog(@"%@%@", stringA, stringB);
    }];
    //输出：我想你嗯   我不想你你豁我
    //说明：若将此结果于合并作对比，我们可以发现他们只是触发next事件的次数所关联对象不一样，是以信号中next事件数量较少的为主
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
